package wsi.exp.exp5;

import java.io.File;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.rygh.core.algorithm.PrecisionRecall;
import org.rygh.core.html.Html;
import org.rygh.core.html.table.HtmlTable;
import org.rygh.core.html.table.TableData;
import org.rygh.core.html.table.TableTuple;
import org.rygh.core.util.UIo;
import org.rygh.core.util.UMath;
import org.rygh.core.util.tex.TexTabular;

import wsi.exp.Exp2TreeToEntity;
import wsi.exp.ExpFolderController;
import wsi.exp.Experiment;
import wsi.function.Function;
import wsi.function.FunctionController;
import wsi.script.AppConfig;
import wsi.script.AppXml;

public class Exp5EntityFusion extends Experiment {

	private final Map<String, PrecisionRecall> precisionRecallByTypeMap = new HashMap<>();
	private final Map<Function, PrecisionRecall> precisionRecallByFunctionMap = new HashMap<>();
	private final PrecisionRecall precisionRecall = new PrecisionRecall();
	private final List<Double> precisions = new LinkedList<>();

	private void appendTex(TableData data, String... types) {
		TableTuple tuple = new TableTuple();
		data.add(tuple);

		for (String t : types) {
			tuple.add(t);
			tuple.add(String.format("%.0f", precisionRecallByTypeMap.get(t)
					.getPrecisionInPercentage()));
		}
	}

	@Override
	public void compute() {
		File dir = ExpFolderController.shared().getFolderForExp5();
		FunctionController fctrl = FunctionController.shared();
		Function function;

		PrecisionRecall pr, pr_type;

		String id;
		int t, c;

		for (File ws : dir.listFiles()) {
			if (!ws.isDirectory())
				continue;

			for (File fdir : ws.listFiles()) {
				if (!ws.isDirectory())
					continue;

				function = fctrl.getFunction(ws.getName(), fdir.getName());

				if (function == null)
					continue;

				if (!Exp2TreeToEntity.isFunctionCorrectlyDetected(function))
					continue;

				id = fctrl.getInputType(function);

				if (precisionRecallByTypeMap.containsKey(id))
					pr_type = precisionRecallByTypeMap.get(id);
				else {
					pr_type = new PrecisionRecall();
					precisionRecallByTypeMap.put(id, pr_type);
				}

				JudgeFileManager jm = new JudgeFileManager(function);

				t = c = 0;

				for (File file : jm.getJudgedFiles()) {
					String[] lines = UIo.readFile(file).split("\r\n");

					for (String l : lines) {
						if (l.trim().isEmpty())
							continue;

						t++;

						if (Boolean.parseBoolean(l))
							c++;
					}
				}

				pr = new PrecisionRecall();
				pr.setRelevant(c);
				pr.setRetrieved(t);
				precisionRecallByFunctionMap.put(function, pr);

				if (pr.getRetrieved() > 0)
					precisions.add(pr.getPrecision());

				pr_type.append(c, t);
				precisionRecall.append(c, t);
			}
		}
	}

	@Override
	public String save() {
		String kdb = AppConfig.shared().getKnowledgeDatabase();

		switch (kdb) {
		case AppXml.YAGO:
			saveTexYago();
			break;

		case AppXml.MBZ:
			saveTexMbz();
			break;

		case AppXml.IMDB:
			saveTexImdb();
			break;

		}

		return saveHtml();
	}

	private String saveHtml() {
		TableData all = new TableData();
		TableData aggr = new TableData();

		TableTuple tuple = new TableTuple();
		aggr.add(tuple);

		tuple.add("Type", "Prec.");

		for (Entry<String, PrecisionRecall> e : precisionRecallByTypeMap
				.entrySet()) {
			tuple = new TableTuple();
			aggr.add(tuple);

			tuple.add(e.getKey(), String.format("%.0f", e.getValue()
					.getPrecisionInPercentage()));
		}

		aggr.sort(1);

		//

		tuple = new TableTuple();
		all.add(tuple);

		tuple.add("Service", "Function", "Prec.");

		for (Entry<Function, PrecisionRecall> e : precisionRecallByFunctionMap
				.entrySet()) {
			tuple = new TableTuple();
			all.add(tuple);

			Function f = e.getKey();

			tuple.add(f.getService(), f.getName());
			tuple.add(String.format("%.0f", e.getValue()
					.getPrecisionInPercentage()));
		}

		all.sort(2);

		//

		Html html = new Html("Experiment 2B");
		html.addElement(AppConfig.shared().getConfigHtml());

		html.addParagraph(String.format("Overall Precision: %.0f%%",
				100. * UMath.getAverage(precisions, 0.)));
		html.newline();
		html.newline();

		HtmlTable table = new HtmlTable(
				"Experiment 2B, Tree to Instance (By Function)", all);
		html.addElement(table);
		html.newline();
		html.newline();

		table = new HtmlTable("Experiment 2B, Tree to Instance (By Type)", aggr);
		html.addElement(table);
		html.newline();
		html.newline();

		//

		String htmlstr = html.toString();

		ExpFolderController folder = ExpFolderController.shared();
		UIo.saveFile(new File(folder.getResultFolder(), ExpFolderController.EXP
				+ "2_result_instance.html"), htmlstr);

		return htmlstr;
	}

	private void saveTexImdb() {
		TableData data = new TableData();
		TableTuple tuple = new TableTuple();
		data.add(tuple);

		for (int i = 0; i < 1; i++)
			tuple.add("Type", "Prec.");

		appendTex(data, "identifier");
		appendTex(data, "movie");

		TexTabular tex = new TexTabular(data);

		ExpFolderController folder = ExpFolderController.shared();
		File dir = folder.getFolderForExp0();

		UIo.saveFile(new File(dir, ExpFolderController.EXP
				+ "2_result_instance_imdb.tex"), tex.toTexBodyString());
	}

	private void saveTexMbz() {
		TableData data = new TableData();
		TableTuple tuple = new TableTuple();
		data.add(tuple);

		for (int i = 0; i < 1; i++)
			tuple.add("Type", "Prec.");

		appendTex(data, "album");
		appendTex(data, "identifier");
		appendTex(data, "person");
		appendTex(data, "song");

		TexTabular tex = new TexTabular(data);

		ExpFolderController folder = ExpFolderController.shared();
		File dir = folder.getFolderForExp0();

		UIo.saveFile(new File(dir, ExpFolderController.EXP
				+ "2_result_instance_mbz.tex"), tex.toTexBodyString());
	}

	private void saveTexYago() {
		TableData data = new TableData();
		TableTuple tuple = new TableTuple();
		data.add(tuple);

		for (int i = 0; i < 1; i++)
			tuple.add("Type", "Prec.");

		// appendTex(data, "album", "country", "person");
		// appendTex(data, "book", "identifier", "publisher");
		// appendTex(data, "city", "movie", "song");

		appendTex(data, "album");
		appendTex(data, "book");
		appendTex(data, "city");
		appendTex(data, "country");
		appendTex(data, "identifier");
		appendTex(data, "movie");
		appendTex(data, "person");
		appendTex(data, "publisher");
		appendTex(data, "song");

		TexTabular tex = new TexTabular(data);

		ExpFolderController folder = ExpFolderController.shared();
		File dir = folder.getFolderForExp0();

		UIo.saveFile(new File(dir, ExpFolderController.EXP
				+ "2_result_instance_yago.tex"), tex.toTexBodyString());
	}
}
